#include <fcntl.h>
#include <gpiod.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#ifndef CONSUMER
#define CONSUMER "RPI_FAN_CTL"
#endif

int getCPUtemperature();

// default line_num = 12
int fan_control(unsigned int line_num, int temp_min, int temp_max)
{
        if (line_num == 0)
        {
                line_num = 12; // if line_num = 0 ,set it to line 12; -> GPIO 12
        }
        const char *chipname = "gpiochip0";
        unsigned int val;
        struct gpiod_chip *chip;
        struct gpiod_line *line12;
        int i, ret;

        int cpu_temp = getCPUtemperature() / 1000;

        chip = gpiod_chip_open_by_name(chipname);
        if (!chip)
        {
                printf("Open chip by name failed. name: %s\n", chipname);
                goto end;
        }

        line12 = gpiod_chip_get_line(chip, line_num);
        if (!line12)
        {
                printf("Get line failed. line_num: %u\n", line_num);
                goto close_chip;
        }

        ret = gpiod_line_request_output(line12, CONSUMER, 0);
        if (ret < 0)
        {
                printf("Request line_num: [%u] as output failed\n", line_num);
                goto release_line12;
        }

#ifdef DEBUG
        printf("cpu_temp = %d\ttemp_min = %d\ttemp_max = %d\n",cpu_temp,temp_min,temp_max);
#endif
        // 如果读取到的cpu温度大于设定的温度值，设置val为1，用于打开gpio端口，输出高电平，用于导通三极管
        if (cpu_temp >= temp_max)
        {
                val = 1;
        }
        // 如果读取到的cpu温度大于设定的温度值，设置val为0，用于关闭gpio端口，输出低电平，用于关断三极管
        if (cpu_temp <= temp_min)
        {
                val = 0;
        }

        ret = gpiod_line_set_value(line12, val);
        if (ret < 0)
        {
                printf("set line_num: [%u] failed. val: %u\n", line_num, val);
                goto release_line12;
        }

release_line12:
        gpiod_line_release(line12);
close_chip:
        gpiod_chip_close(chip);
end:
        return 0;
}

int getCPUtemperature(void)
{
        int fd;
        int re = 0, i;
        char buff[10];
        fd = open("/sys/class/thermal/thermal_zone0/temp", O_RDONLY);
        if (fd < 0)
        {
                perror("open:/sys/class/thermal/thermal_zone0/temp error");
                exit(0);
        }
        i = read(fd, buff, 10);
        if (i < 0)
        {
                perror("read:/sys/class/thermal/thermal_zone0/temp error");
                exit(0);
        }
        re = atoi(buff);
        close(fd);
        // printf("re=%d size=%d\n",re,i);
        return re;
}

int main(int argc, char *argv[])
{
        // char buff[256];
        // memset(buff, 0x00, sizeof(buff));
        // sprintf(buff, "CPU Temp %d`C", getCPUtemperature() / 1000);
        // printf("%s", buff);
        // fan_control(12, 45, 52);

        unsigned int line_num_n = 0;
        unsigned int min_temp_n = 0;
        unsigned int max_temp_n = 0;

        int opt;
        int option_index = 0;
        static struct option long_options[] = {
            {"line_num", required_argument, NULL, 0},
            {"min_temp", required_argument, NULL, 0},
            {"max_temp", required_argument, NULL, 0},
            {"help", no_argument, NULL, 'h'},
            {0, 0, 0, 0}};

        while ((opt = getopt_long(argc, argv, "h", long_options, &option_index)) != -1)
        {
                switch (opt)
                {
                case 0:
                        if (strcmp(long_options[option_index].name, "line_num") == 0)
                        {
                                line_num_n = atoi(optarg);
                        }
                        else if (strcmp(long_options[option_index].name, "min_temp") == 0)
                        {
                                min_temp_n = atoi(optarg);
                        }
                        else if (strcmp(long_options[option_index].name, "max_temp") == 0)
                        {
                                max_temp_n = atoi(optarg);
                        }
                        else if (strcmp(long_options[option_index].name, "help") == 0)
                        {
                                printf("usage: \n\t%s --line_num 12 --min_temp 45 --max_temp 52", argv[0]);
                        }
                        break;
                case 'h':
                        printf("usage: \n\t%s --line_num 12 --min_temp 45 --max_temp 52\n", argv[0]);
                        exit(EXIT_SUCCESS);
                        break;
                default:
                        fprintf(stderr, "usage: \n\t%s --line_num 12 --min_temp 45 --max_temp 52", argv[0]);
                        exit(EXIT_SUCCESS);
                        break;
                }
        }
        if (line_num_n == 0 || min_temp_n == 0 || max_temp_n == 0) {
                exit(EXIT_FAILURE);
        }
        fan_control(line_num_n, min_temp_n, max_temp_n);

        return 0;
}